
package com.htj.erp.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.htj.erp.dao.DeliveryDao;
import com.htj.erp.dao.HRecvAddressDao;
import com.htj.erp.dao.OrderbDao;
import com.htj.erp.dao.OrderhDao;
import com.htj.erp.dao.RouteDisDao;
import com.htj.erp.dao.mybatis.DeliveryMapper;
import com.htj.erp.exception.BusinessException;
import com.htj.erp.model.jpa.Delivery;
import com.htj.erp.model.jpa.HRecvAddress;
import com.htj.erp.model.jpa.Orderb;
import com.htj.erp.model.jpa.Orderh;
import com.htj.erp.model.jpa.RouteDis;
import com.htj.erp.model.mybatis.DeliveryPO;
import com.htj.erp.util.BaiduMapUtil;
import com.htj.erp.util.ExcelUtil;
import com.htj.erp.util.PathVo;
import com.htj.erp.vo.DeliveryVO;
import com.htj.erp.vo.LocationVo;
import com.htj.erp.vo.OrderbVO;
import com.kedacom.core.utils.ApplicationUtil;
import com.kedacom.security.service.GenericCpsService;
import com.kedacom.utils.DateFormatUtil;
import com.kedacom.utils.StringUtil;
/**
 * 
 *
 * 
 * DeliveryService
 * delivery service 处理类
 * 这个基本类一般继承com.kedacom.security.service.GenericCpsService
 * 如果自己实现转换类，通过重写getXXConveter方法。
 * chenghongtao
 * 2016-11-08 16:33:14
 * HTJ
 * @version 1.0.0
 *
 */
@Service
public class DeliveryService extends GenericCpsService<Delivery,DeliveryPO,DeliveryVO,Long>  {


	@Resource
	private DeliveryDao deliveryDao;

	@Resource
	private DeliveryMapper deliveryMapper;

	@Resource
	private OrderbDao orderbDao;

	@Resource
	private RouteDisDao routeDisDao;
	
	@Resource
	private OrderhDao orderhDao;

	@Resource
	private HRecvAddressDao hRecvAddressDao;
	/**
	 * 获取jpa的dao
	 */
	@Override
	protected  DeliveryDao getEntityJpaDao ()
	{
		return this.deliveryDao;
	}


	/**
	 * 获取 mubatis 的dao
	 */
	@Override
	protected  DeliveryMapper getEntityDao ()
	{
		return this.deliveryMapper;
	}



	/**
	 * 
	 * saveOrUpdate 保存或者更新
	 * @param deliveryVO
	 * @return
	 *DeliveryVO
	 * @exception
	 * @since  1.0.0
	 */
	public DeliveryVO saveOrUpdate(DeliveryVO deliveryVO) throws Exception
	{

		if(StringUtil.isNotEmpty(deliveryVO.getOrderbData()))
		{

			deliveryVO.setOrderbs(JSONArray.parseArray(deliveryVO.getOrderbData(), OrderbVO.class));
		}

		if(deliveryVO.getId() == null || deliveryVO.getId() == 0L)
		{
			return this.add(deliveryVO);
		}
		else
		{
			return this.update(deliveryVO);
		}

	}

	/**
	 * 重写保存方法，因为牵涉到子表处理
	 */

	public void closeDelivery(Long id) throws Exception{
		Delivery delivery = this.getEntityJpaDao().findOne(id);
		if(delivery == null || !delivery.getStatus().equals(Delivery.STATUS_SENDING))
		{
			throw new BusinessException("未找到发货单，或者发货单状态不对");
		}

		List<Orderb> existOrderb = this.orderbDao.findByDeliveryId(id);
		HashSet<Long> hids = new HashSet<Long>();
		for(Orderb b : existOrderb)
		{
			b.setDeliveryId(id);
			b.setIsPlanSend(Delivery.STATUS_SENDED);
			b.setDeliveryman(delivery.getSender());
			b.setSendDate(delivery.getSendDate());
			this.orderbDao.save(b);
			//设置正在送货
			hids.add(b.getOrderh().getId());
		}

		for(Long hid : hids)
		{
			Orderh orderh = this.orderhDao.findOne(hid);
			boolean isSended =true;
			for(Orderb b : orderh.getOrderbs())
			{
				//有没有送完的就返回
				if(!Delivery.STATUS_SENDED.equals(b.getIsPlanSend()))
				{
					isSended = false;
					break;
				}
			}
			if(isSended)
			{
				orderh.setStatus(Orderh.STATUS_CLOSED);
				this.orderhDao.save(orderh);
			}
		}

		delivery.setStatus(Delivery.STATUS_SENDED);
		this.getEntityJpaDao().save(delivery);
	}
	/**
	 * 重写保存方法，因为牵涉到子表处理
	 */

	public void submitSending (Long id) throws Exception{
		Delivery delivery = this.getEntityJpaDao().findOne(id);
		if(delivery == null || !delivery.getStatus().equals(Delivery.STATUS_INIT))
		{
			throw new BusinessException("未找到发货单，或者发货单已经提交");
		}

		List<Orderb> existOrderb = this.orderbDao.findByDeliveryId(id);
		HashSet<Long> hids = new HashSet<Long>();
		for(Orderb b : existOrderb)
		{
			b.setDeliveryId(id);
			if(!b.getIsPlanSend().equals(Delivery.STATUS_INIT))
			{
				throw new BusinessException(b.getProductName() + ":" + b.getRecvName() + "已经安排送货，无法提交。");
			}
			b.setIsPlanSend(Delivery.STATUS_SENDING);
			b.setDeliveryman(delivery.getSender());
			b.setSendDate(delivery.getSendDate());
			//设置正在送货
			hids.add(b.getOrderh().getId());
		}
		this.orderbDao.save(existOrderb);

		for(Long hid : hids)
		{
			orderhDao.updateStatus(hid,Orderh.STATUS_SENDING);
		}

		delivery.setStatus(Delivery.STATUS_SENDING);
		this.getEntityJpaDao().save(delivery);
	}
	
	public void cancelSending (Long id) throws Exception{
		Delivery delivery = this.getEntityJpaDao().findOne(id);
		if(delivery == null)
		{
			throw new BusinessException("未找到发货单，或者发货单已经提交");
		}

		List<Orderb> existOrderb = this.orderbDao.findByDeliveryId(id);
		HashSet<Long> hids = new HashSet<Long>();
		for(Orderb b : existOrderb)
		{
			b.setDeliveryId(id);
			b.setIsPlanSend(Delivery.STATUS_INIT);
			b.setDeliveryman("");
			b.setSendDate(null);
			//设置正在送货
			hids.add(b.getOrderh().getId());
		}
		this.orderbDao.save(existOrderb);

		for(Long hid : hids)
		{
			List<Orderb> orderbList = this.orderbDao.findByOrderh(hid);
			Integer status = Orderh.STATUS_SUBMIT;
			for(Orderb b1 : orderbList)
			{
				if(!b1.getIsPlanSend().equals(Delivery.STATUS_INIT))
				{
					status =Orderh.STATUS_SENDING;
					break;
				}
			}
			orderhDao.updateStatus(hid,status);
		}

		delivery.setStatus(Delivery.STATUS_INIT);
		this.getEntityJpaDao().save(delivery);
	}

	/**
	 * 重写保存方法，因为牵涉到子表处理
	 */
	@Override
	public DeliveryVO add (DeliveryVO vo) throws Exception{
		Delivery entity = this.getMoConverter().convert(Delivery.class, vo);

		entity.setStatus(Delivery.STATUS_INIT);
		entity = save(entity);
		for(OrderbVO bvo : vo.getOrderbs())
		{
			Orderb orderb= this.orderbDao.findOne(bvo.getId());
			orderb.setDeliveryId(entity.getId());
			this.orderbDao.save(orderb);
		}
		return getVoConverter().convert(DeliveryVO.class, entity); 
	}

	/**
	 * 重写update方法。
	 */
	@Override
	public DeliveryVO update (DeliveryVO vo) throws Exception{
		Delivery entity = this.getMoConverter().convert(Delivery.class, vo);

		Delivery dbentity = this.getEntityJpaDao().findOne(vo.getId());
		if(!Delivery.STATUS_INIT.equals(dbentity.getStatus()))
		{
			throw new BusinessException("非草稿状态不可以修改。");
		}

		List<Orderb> existOrderb = this.orderbDao.findByDeliveryId(vo.getId());

		for(Orderb b : existOrderb)
		{
			b.setDeliveryId(null);
			b.setIsPlanSend(0);
			b.setDeliveryman(null);
			b.setSendDate(null);
			this.orderbDao.save(b);
		}

		for(OrderbVO bvo : vo.getOrderbs())
		{
			Orderb orderb= this.orderbDao.findOne(bvo.getId());
			orderb.setDeliveryId(vo.getId());
			this.orderbDao.save(orderb);
		}
		entity = save(entity);
		return getVoConverter().convert(DeliveryVO.class, entity); 
	}	
	@Override
	public void delById(Long id) throws Exception {
		Delivery delivery = this.getEntityJpaDao().findOne(id);
		if(delivery == null)
			return;
		if(!delivery.getStatus().equals(Delivery.STATUS_INIT))
			throw new BusinessException("该订单"+ DateFormatUtil.formaDatetTime(delivery.getSendDate())+"已经提交确认，不能删除。");
		//删除子表
		List<Orderb> existOrderb = this.orderbDao.findByDeliveryId(id);

		for(Orderb b : existOrderb)
		{
			b.setDeliveryId(null);
			b.setIsPlanSend(0);
			b.setDeliveryman(null);
			b.setSendDate(null);
			this.orderbDao.save(b);
		}

		this.getEntityJpaDao().delete(id);
	}


	@Override
	public void delByIds(Long[] ids) throws Exception {
		for(Long id : ids)
		{
			delById(id);
		}
	}


	/**
	 * 计算送货顺序
	 * @param id
	 */
	public PathVo calSendWay(LocationVo start,Long id,boolean usingMaxDis) throws Exception
	{
		Delivery dbentity = this.getEntityJpaDao().findOne(id);
		List<Orderb> existOrderb = this.orderbDao.findByDeliveryId(id);
		List<LocationVo> list = new ArrayList<>();
		Map<Long,List<Orderb>> locMap = new HashMap<Long,List<Orderb>>();
		if(existOrderb.size() == 0)
			throw new BusinessException("没有添加送货订单。");
		final HashMap<String,RouteDis> tmpMap = new HashMap<String,RouteDis>();
		for(Orderb orderb : existOrderb)
		{
			HRecvAddress recv = this.hRecvAddressDao.findOne(orderb.getRecvId());
			if(recv == null)
				throw new BusinessException("地址没有匹配无法计算。");
			if(!locMap.containsKey(recv.getId()))
			{
				LocationVo vo = new LocationVo();
				vo.setAddress(orderb.getRecvAdd());
				vo.setName(orderb.getRecvName());
				vo.setRegion("苏州");
				vo.setRecvId(recv.getId());
				vo.setLatitude(recv.getLatitude());
				vo.setLongitude(recv.getLongitude());
				locMap.put(recv.getId(), new ArrayList<Orderb>());
				list.add(vo);
			}
			locMap.get(recv.getId()).add(orderb);
		}
		

		PathVo path = BaiduMapUtil.routePlanningNew(start,list,start,usingMaxDis,new RouteDisManger() {
			
			@Override
			public void saveDis(LocationVo src, LocationVo des, Integer dis) {
				if(src.equals(des))
					return;
				RouteDis rd = new RouteDis();
				rd.setSrcAddr(src.getAddress());
				rd.setSrcLat(src.getLatitude());
				rd.setSrcLong(src.getLongitude());
				rd.setSrcName(src.getName());
				rd.setDesAddr(des.getAddress());
				rd.setDesLat(des.getLatitude());
				rd.setDesLong(des.getLongitude());
				rd.setDesName(des.getName());
				rd.setDistance(dis);
				String key  = String.format("%s-%s-%s-%s", rd.getSrcLong(),rd.getSrcLat(),rd.getDesLong(),rd.getDesLat());
				System.out.println(key);
				tmpMap.put(key, rd);
				routeDisDao.save(rd);
				}
			
			@Override
			public RouteDis getDis(LocationVo src, LocationVo des) {
				
				if(src.equals(des))
				{
					RouteDis rd = new RouteDis();
					rd.setSrcAddr(src.getAddress());
					rd.setSrcLat(src.getLatitude());
					rd.setSrcLong(src.getLongitude());
					rd.setSrcName(src.getName());
					rd.setDesAddr(des.getAddress());
					rd.setDesLat(des.getLatitude());
					rd.setDesLong(des.getLongitude());
					rd.setDesName(des.getName());
					rd.setDistance(0);
					return rd;
				}
				String key  = String.format("%s-%s-%s-%s", src.getLongitude(),src.getLatitude(),des.getLongitude(),des.getLatitude());
				if(tmpMap.containsKey(key))
					return tmpMap.get(key);
				
				List<RouteDis> dis = routeDisDao.findByLongLat(src.getLongitude(),src.getLatitude(),des.getLongitude(),des.getLatitude());
				if(dis.size() >= 1)
				{
					tmpMap.put(key, dis.get(0));
					return dis.get(0);
				}
				
				
				
				return null;
			}
		});
		int t = 1;
		for(int i =0; i < path.getLoc().size(); i++)
		{
			LocationVo vo = path.getLoc().get(i);
			System.out.println(vo.getName());
			if(vo.getRecvId() != null && vo.getRecvId() >0)
			{
				List<Orderb> orderbList = locMap.get(vo.getRecvId());
				for(Orderb tmp : orderbList)
				{
					tmp.setSendWay(t);
				}
				t ++;
			}
		}
		
		this.orderbDao.save(existOrderb);
		return path;
	}
	
	
	
	public void export(Long id,OutputStream os) throws Exception
	{
		String file = ApplicationUtil.getAppAbsolutePath() + File.separator + "WEB-INF" + File.separator 
				+ "tpl" + File.separator + "delivery_tpl.xls";
//		File f = new File(outputFile);
//		if(f.exists())
//			f.mkdirs();
		List<Orderb> existOrderb  = this.orderbDao.findByDeliveryId(id, new Sort(Direction.ASC, "sendWay"));
		HSSFWorkbook workbook = null;
		FileInputStream fis = null;
//		FileOutputStream fos = null;
//		File outFile = new File(f.getAbsolutePath(),System.currentTimeMillis() + ".xls");
		
		try{
//			fos = new FileOutputStream(outFile);
			fis = new FileInputStream(file);
			workbook = new HSSFWorkbook(fis);
			HSSFSheet sheet = workbook.getSheetAt(0);
			int j =1;
			int size = existOrderb.size();
			for(int i =1; i < size; i++)
			{
				HSSFRow row =  sheet.createRow(i+1);
				ExcelUtil.copyRow(workbook, sheet.getRow(1), row, false);
			}
			Map<String,Long> map = new HashMap<String,Long>();
			Map<String,Orderb> specmap = new HashMap<String,Orderb>();
			for(Orderb orderb : existOrderb)
			{
				HSSFRow row = null;
				row = sheet.getRow(j);
				row.getCell(0).setCellValue(orderb.getProductName());
				row.getCell(1).setCellValue(orderb.getProductSpec());
				row.getCell(2).setCellValue(orderb.getUnit());
				row.getCell(3).setCellValue(orderb.getProductNum());
				row.getCell(4).setCellValue(orderb.getUnitPrice());
				row.getCell(5).setCellValue(orderb.getTotalPrice());
				row.getCell(6).setCellValue(orderb.getRecvName());
				row.getCell(7).setCellValue(orderb.getRecvAdd());
				row.getCell(8).setCellValue(orderb.getRecvTel());
				row.getCell(9).setCellValue(orderb.getSendWay()==null ?0d:orderb.getSendWay());
				if(map.containsKey(orderb.getProductName()))
				{
					map.put(orderb.getProductName(), map.get(orderb.getProductName()) + orderb.getProductNum());
				}
				else
				{
					map.put(orderb.getProductName(), orderb.getProductNum());
				}
				specmap.put(orderb.getProductName(), orderb);
				j++;
			}
			
			
			size = map.size();
			sheet = workbook.getSheetAt(1);
			for(int i =1; i < size; i++)
			{
				HSSFRow row =  sheet.createRow(i+1);
				ExcelUtil.copyRow(workbook, sheet.getRow(1), row, false);
			}
			
			j = 1;
			for(String key : map.keySet())
			{
				HSSFRow row = null;
				row = sheet.getRow(j);
				row.getCell(0).setCellValue(key);
				row.getCell(1).setCellValue(specmap.get(key).getProductSpec());
				row.getCell(2).setCellValue(specmap.get(key).getUnit());
				row.getCell(3).setCellValue(map.get(key));
				j++;
			}
			
			workbook.write(os);
			
		}finally{
			if(workbook != null)
				workbook.close();
			if(fis != null)
				fis.close();
//			if(fos != null)
//			{
//				fos.flush();
//				fos.close();
//			}
			
		}
//		return outFile;
	}

}
